#include <string.h>
#include <stdlib.h>
#include "list.h"
#include "lexical.h"
#include "error.h"
#include "token_list.h"
#include "common.h"

LIST_HEAD(tk_buffer_g);
LIST_HEAD(tk_uesd_g);


void move_token_to_buffer(void)
{
	tk_node_t *new = calloc(1, sizeof(tk_node_t));
	if(!new) {
		SYSTEM_FATAL_ERR(MEM_ALLOC_FAILED);
		return;
	}
	
	new->tk = scanner_get_cur_token();
	new->line = scanner_get_line_num();
	new->col = scanner_get_col_num();
	
	if(new->tk == ID){
		new->pval = malloc(strlen(scanner_get_token_id())+1);
		if(!new->pval) {
            free(new);
			SYSTEM_FATAL_ERR(MEM_ALLOC_FAILED);
			return;
		}
		strcpy(new->pval, scanner_get_token_id());
		
	} else if(new->tk == STRING) {
		new->pval = malloc(strlen(scanner_get_token_str())+1);
		if(!new->pval) {
            free(new);
			SYSTEM_FATAL_ERR(MEM_ALLOC_FAILED);
			return;
		}

		strcpy(new->pval, scanner_get_token_str());
		
	} else if(new->tk == NUM) {
		new->pval = malloc(sizeof(int));
		if(!new->pval) {
            free(new);
			SYSTEM_FATAL_ERR(MEM_ALLOC_FAILED);
			return;
		}

		*(int *)new->pval = scanner_get_token_num();
		
	} else if(new->tk == CHARA) {
		new->pval = malloc(sizeof(char));
		if(!new->pval) {
            free(new);
			SYSTEM_FATAL_ERR(MEM_ALLOC_FAILED);
			return;
		}		
		*(char *)new->pval = scanner_get_token_ch();

	}

	list_add_tail(&new->entry, &tk_buffer_g);
}

tk_node_t *token_dequeue(struct list_head *head)
{
	if(list_empty(head)) {
        return NULL;
    }
		
	struct list_head *first = head->next;
	list_del(first);
	return container_of(first, tk_node_t, entry);
}

void put_token_back(int num)
{
    int left = get_list_len(&tk_uesd_g);

    if(num > left)
        num = left;
    while(num--) {
        struct list_head *last = tk_uesd_g.prev;
        list_move(last, &tk_buffer_g);
    }
}


void free_token(tk_node_t *t)
{
    if(t == NULL)
        return;

	if(t->pval)
		free(t->pval);

	free(t);
}


void __destroy_token_queue(struct list_head *head)
{
	tk_node_t *token;
	while(token = token_dequeue(head)) {
		free_token(token);
	}
}


void destroy_token_queue(void)
{
	__destroy_token_queue(&tk_uesd_g);
	__destroy_token_queue(&tk_buffer_g);
}

void print_token(tk_node_t *node)
{
	if(!node)
        return;

	switch(node->tk){
		case STRING:
			printf(HI_RED);
			printf("\"");
			char *p = node->pval;
			while(*p){
				show_ch_including_escape(*p);
				p++;
			}
			printf("\"");
			break;
						
		case NUM:
			printf(YEL);
			printf("%d", *(int *)node->pval);
			break;
			
		case CHARA:
			printf(HI_PUR);
			printf("\'");			
			show_ch_including_escape(*(char *)node->pval);
			printf("\'");
			break;
			
		case ID:
			printf(HI_WHI);
			printf("%s", (char *)node->pval);
			break;			
            
		case BREAK ... WHILE:
			printf(HI_YEL);
			printf("%s", syms_names[node->tk]);
			break;	
            
		case ADD ... NEQU: // 注意...两边都有空格
			printf(HI_GRE);
			printf("%s", syms_names[node->tk]);
			break;
		case COMMA ... RBRACES: // 注意...两边都有空格
			printf(HI_BLU);
			printf("%s", syms_names[node->tk]);
			break;	
		default:
			break;
	}
	printf(CLOSE);	
}


void show_token_with_fmt(tk_node_t *node)
{
	//void (*pre_do)(void) = fmt_tab[node->tk].pre_do;
	//void (*post_do)(void) = fmt_tab[node->tk].post_do;

	//if(pre_do)
	//	pre_do();
	
	print_token(node);
	
	//if(post_do)
		//post_do();
}

symbol_e old_token_g;
// -1 表示全部出队
void tk_list_flush(symbol_e stop, struct list_head *head)
{
	tk_node_t *top = token_dequeue(head);
	symbol_e token;
	
	while(top){
		show_token_with_fmt(top);
		token = top->tk;
		old_token_g = token;
		free_token(top);
		if(token == stop) // 一直出队到 stop
			break;
		top = token_dequeue(head);
	}
}
